package com.zenika.zentracker.hibernate.info;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * This class is used to collect information in the case Hibernate Removes a Collection.
 * 
 * @see CollectionInformation
 * @see AbstractCollectionInformation
 * @author Zenika
 */
public class CollectionUpdate extends AbstractCollectionInformation implements CollectionInformation {

    private List addedObjects = new ArrayList();
    private List removedObjects = new ArrayList();

    /**
     * The flush index, the added objects and the removed objects are needed to create a CollectionUpdate Information.
     * 
     * @param flushNumber the flush index before a transaction completion
     * @param addedObjects the newly added objects into the collection
     * @param removedObjects the removed objects from the collection
     */
    public CollectionUpdate(final int flushNumber, final Serializable storedSnapshot, final Serializable snapshot) {
        super(flushNumber);

        if (storedSnapshot instanceof Map && snapshot instanceof Map) {
            this.addedObjects.addAll(findAddedObjects(((Map) storedSnapshot).values(), ((Map) snapshot).values()));
            this.removedObjects.addAll(findRemovedObjects(((Map) storedSnapshot).values(), ((Map) snapshot).values()));
        } else {
            this.addedObjects.addAll(findAddedObjects((List) storedSnapshot, (List) snapshot));
            this.removedObjects.addAll(findRemovedObjects((List) storedSnapshot, (List) snapshot));
        }
    }

    /**
     * Find the added objects in a Hibernate collection by comparing the Current Snapshot of a collection with the
     * Stored Snapshot.
     * 
     * @param storedSnapshot
     * @param snapshot
     * @return List of added objects.
     */
    private List findAddedObjects(Collection storedSnapshot, Collection snapshot) {
        List snapshotValues = new ArrayList(snapshot);
        List storedSnapshotValues = new ArrayList(storedSnapshot);

        snapshotValues.removeAll(storedSnapshotValues);

        return snapshotValues;
    }

    /**
     * Find the removed objects in a Hibernate collection by comparing the Stored Snapshot of a collection with the
     * Current Snapshot.
     * 
     * @param storedSnapshot
     * @param snapshot
     * @return List of removed objects.
     */
    private List findRemovedObjects(Collection storedSnapshot, Collection snapshot) {
        List snapshotValues = new ArrayList(snapshot);
        List storedSnapshotValues = new ArrayList(storedSnapshot);

        storedSnapshotValues.removeAll(snapshotValues);

        return storedSnapshotValues;
    }

    public String toString() {
        return logAddingElementsInCollection(addedObjects) + logRemovingElementsFromCollection(removedObjects);
    }

}
